package com.seqb.common.task;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.extra.mail.MailUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.seqb.common.config.RedisConfig;
import com.seqb.common.config.SeqbConfig;
import com.seqb.common.utils.RedisUtils;
import com.seqb.utils.DateUtils;
import com.seqb.utils.JsonUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.ssl.SSLContexts;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.nio.charset.Charset;
import java.util.*;

/**
 * @author lilinshen
 * @title 动态代理job
 * @description 请填写相关描述
 * @date 2022/4/28
 */
public class DynamicAgentJob implements Job {

    private static final Logger LOGGER = LoggerFactory.getLogger(DynamicAgentJob.class);
    public HttpHeaders headers = new HttpHeaders();
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private SeqbConfig seqbConfig;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        try {
            Object taskParams = redisUtils.get("taskParams");
            List<String> accountLists = new ArrayList<>();
            List<String> requestUrlLists = new ArrayList<>();
            if (null != taskParams) {
                JSONArray parseArray = JSON.parseArray(taskParams.toString());
                for (int i = 0; i < parseArray.size(); i++) {
                    JSONObject item = parseArray.getJSONObject(i);
                    String type = item.getString("type");
                    if ("DynamicAgentJob".equals(type)) {
                        JSONArray value = item.getJSONArray("value");
                        for (int j = 0; j < value.size(); j++) {
                            JSONObject jsonObject = value.getJSONObject(j);
                            String key = jsonObject.getString("key");
                            if (key.indexOf("RequestUrl") >= 0) {
                                requestUrlLists.add(jsonObject.getString("value"));
                            }
                            if (key.indexOf("Account") >= 0) {
                                accountLists.add(jsonObject.getString("value"));
                            }
                        }
                    }
                }
            }
            LOGGER.info("动态代理IP定时任务开始-----------" + DateUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));

            for (int i = 0; i < accountLists.size(); i++) {
                headers = new HttpHeaders();
                headers.add("Host", "www.siyetian.com");
                String accounts = accountLists.get(i);
                String username = accounts.split("&")[0];
                String password = accounts.split("&")[1];
                String meal = accounts.split("&")[2];
                if (executeLogin(username, password)) {
                    if (executeSignDaily()) {
                        String agentDq = executeApisCreate(meal);
                        if (StringUtils.isNotEmpty(agentDq)) {
                            executeDynamicAgent(username, agentDq, requestUrlLists);
                        }
                    }
                }
                Thread.sleep(10000);
            }
            LOGGER.info("动态代理IP定时任务结束-----------" + DateUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * login登录，获取cookie
     *
     * @return
     */
    public boolean executeLogin(String username, String password) {
        try {
            RestTemplate restTemplate = new RestTemplate();
            String requestUrl = "http://www.siyetian.com/login.html";
            HttpMethod httpMethod = HttpMethod.POST;
            HttpHeaders headersTemp = new HttpHeaders();
            headersTemp.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
            paramsMap.add("username", username);
            paramsMap.add("password", password);
            HttpEntity httpEntity = new HttpEntity(paramsMap, headersTemp);
            ResponseEntity<String> responseEntity = restTemplate.exchange(requestUrl, httpMethod, httpEntity, String.class);
            HttpStatus status = responseEntity.getStatusCode();
            if (status.equals(HttpStatus.OK)) {
                String entityBody = responseEntity.getBody();
                entityBody = StringEscapeUtils.unescapeJava(entityBody);
                JSONObject result = JSON.parseObject(entityBody);
                LOGGER.info("动态ip登录任务操作：" + result.getString("info"));
                String code = result.getString("code");
                if ("1".equals(code)) {
                    //将cookie写入header
                    List<String> cookies = responseEntity.getHeaders().get("Set-Cookie");
                    for (String cookieStr : cookies) {
                        String[] cookieArr = cookieStr.split(";");
                        String cookieItem = cookieArr[0] + " ;limit=20 ;lang=zh-cn ";
                        headers.add("Cookie", cookieItem);
                    }
                    return true;
                }
            }
        } catch (Exception e) {
            System.out.println("动态ip登录任务操作：" + e.getMessage());
        }
        return false;
    }

    /**
     * 签到，领取20个ip的套餐
     *
     * @return
     */
    public boolean executeSignDaily() {
        Object flagRedis = redisUtils.get(RedisConfig.COM_PREFIX + this.getClass().getSimpleName());
        try {
            RestTemplate restTemplate = new RestTemplate();
            String requestUrl = "http://www.siyetian.com/member/receive.html";
            HttpMethod httpMethod = HttpMethod.GET;
            Map<String, Object> paramsMap = new HashMap<>();
            HttpEntity httpEntity = new HttpEntity(JsonUtils.beanToJson(paramsMap), headers);
            ResponseEntity<String> responseEntity = restTemplate.exchange(requestUrl, httpMethod, httpEntity, String.class);
            HttpStatus status = responseEntity.getStatusCode();
            if (status.equals(HttpStatus.OK)) {
                String entityBody = responseEntity.getBody();
                entityBody = StringEscapeUtils.unescapeJava(entityBody);
                JSONObject result = JSON.parseObject(entityBody);
                LOGGER.info("动态ip每天签到任务操作：" + result.getString("code"));
                return true;
            }
        } catch (Exception e) {
            System.out.println("动态ip每天签到任务执行失败：" + e.getMessage());

            if (null == flagRedis) {
                //设置一天失效时间的key，每天只发一次邮件通知
                redisUtils.set(RedisConfig.COM_PREFIX + this.getClass().getSimpleName(), true, 86400);
                //发送邮件通知唯佳生活签到失效
                MailUtil.send("lilinshen@cecjx.com", "唯佳生活定时任务", "唯佳生活定时任务，用户cookie失效，请及时更新用户cookie信息。", false);
            }

            MailUtil.send("lilinshen@cecjx.com", "动态代理IP定时任务", "动态ip每天签到任务执行失败，cookie失效", true);
        }
        return false;
    }


    /**
     * 套餐，提取api，获取生成api链接
     *
     * @return
     */
    public String executeApisCreate(String meal) {
        try {
            RestTemplate restTemplate = new RestTemplate();
            String requestUrl = "http://www.siyetian.com/apis_create.html";
            HttpMethod httpMethod = HttpMethod.POST;
            HttpHeaders headersTemp = new HttpHeaders();
            headersTemp.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
            paramsMap.add("meal", meal);
            paramsMap.add("limit", "1");
            paramsMap.add("type", "0");
            paramsMap.add("time", "0");
            paramsMap.add("split", "0");
            paramsMap.add("area", "0");
            paramsMap.add("repeat", "0");
            headersTemp.addAll(headers);
            HttpEntity httpEntity = new HttpEntity(paramsMap, headersTemp);
            ResponseEntity<String> responseEntity = restTemplate.exchange(requestUrl, httpMethod, httpEntity, String.class);
            HttpStatus status = responseEntity.getStatusCode();
            if (status.equals(HttpStatus.OK)) {
                String entityBody = responseEntity.getBody();
                entityBody = StringEscapeUtils.unescapeJava(entityBody);
                JSONObject result = JSON.parseObject(entityBody);
                String code = result.getString("code");
                if ("1".equals(code)) {
                    //将cookie写入header
                    LOGGER.info("动态ip获取生成api链接任务操作成功：" + result.getString("info"));
                    String info = result.getString("info");
                    return info;
                }
            }
        } catch (Exception e) {
            System.out.println("动态ip登录任务操作：" + e.getMessage());
        }
        return "";
    }

    /**
     * 通过api，获取代理ip+port
     */
    public void executeDynamicAgent(String username, String agentDq, List requestUrlLists) {
        //保存到文件里面
        String path = seqbConfig.getUploadPath() + "dynamic/" + DateUtil.format(new Date(), "yyyy-MM") + "/" + DateUtil.format(new Date(), "yyyy-MM-dd") + ".txt";
        FileUtil.appendUtf8String("获取账号：" + username + FileUtil.getLineSeparator(), new File(path));
        for (int i = 0; i < 20; i++) {
            String result = HttpUtil.get(agentDq);
            try {
                System.out.println("从接口获取回来的动态代理ip:" + result);
                if (result.contains("code")) {
                    executeFileAgent(path, requestUrlLists);
                    break;
                } else {
                    FileUtil.appendUtf8String(result + FileUtil.getLineSeparator(), new File(path));
                }

                //代理请求接口
                String ip = result.split(":")[0];
                int port = Integer.parseInt(result.split(":")[1]);
                requestUrlLists.stream().forEach(url -> {
                    doExecuteDynamicAgent(String.valueOf(ip), Integer.valueOf(String.valueOf(port)), String.valueOf(url));

                    try {
                        char sleepTime = RandomUtil.randomNumber();
                        Thread.sleep(100 * sleepTime);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
            } catch (Exception e) {

            }
        }
    }

    /**
     * 执行已经保存代理ip+port的文件
     */
    public void executeFileAgent(String path, List requestUrlLists) {
        List<String> ipPorts = FileUtil.readLines(path, Charset.defaultCharset());
        if (BeanUtil.isEmpty(ipPorts)) {
            return;
        }
        ipPorts.stream().forEach(item -> {
            if (item.split(":").length <= 1) {
                return;
            }
            String ip = item.split(":")[0];
            int port = Integer.parseInt(item.split(":")[1]);

            requestUrlLists.stream().forEach(url -> {
                doExecuteDynamicAgent(String.valueOf(ip), Integer.valueOf(String.valueOf(port)), String.valueOf(url));
                try {
                    char sleepTime = RandomUtil.randomNumber();
                    Thread.sleep(100 * sleepTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        });
    }

    /**
     * 真正的发起请求url
     */
    public void doExecuteDynamicAgent(String ip, int port, String url) {
        //记录是否失效
        boolean flag = true;
        try {
            RestTemplate restTemplate = getRestTemplate(ip, port);
            HttpMethod httpMethod = HttpMethod.GET;
            Map<String, Object> paramsMap = new HashMap<>();
            HttpEntity httpEntity = new HttpEntity(paramsMap, null);
            ResponseEntity<String> responseEntity = restTemplate.exchange(url, httpMethod, httpEntity, String.class);
            HttpStatus status = responseEntity.getStatusCode();
            if (!status.equals(HttpStatus.OK)) {
                flag = false;
            }
        } catch (Exception e) {
            flag = false;
        }
        if (!flag) {
            LOGGER.info("动态代理定时任务,执行失败。ip:{},port:{},url:{}", ip, port, url);
        } else {
            LOGGER.info("动态代理定时任务,执行成功。ip:{},port:{},url:{}", ip, port, url);
        }
    }

    /**
     * 获取带代理的resttemplate对象
     */
    public RestTemplate getRestTemplate(String ip, int port) throws Exception {
        TrustStrategy acceptingTrustStrategy = (x509Certificates, authType) -> true;
        SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
        SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
        //设置代理端口和不进行重点向跳转
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create().disableRedirectHandling()
                .setProxy(new HttpHost(ip, port, "http"));
        httpClientBuilder.setSSLSocketFactory(socketFactory);
        HttpClient httpClient = httpClientBuilder.build();
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setHttpClient(httpClient);
        factory.setReadTimeout(6000);
        factory.setConnectTimeout(6000);
        return new RestTemplate(factory);
    }

}
